package tech.yixiyun.framework.kuafu.plugins.hotdeploy;

import org.apache.commons.io.monitor.FileAlterationListener;
import org.apache.commons.io.monitor.FileAlterationObserver;

import java.io.File;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 监控文件变动，一旦变动就重新加载，让变动生效
 * 需要配合Jrebel使用
 * @author Boolone
 *
 */
public class HotDeployListener implements FileAlterationListener {

	private String rootPath;
	/**
	 * 记录该类上次改动时间，防止短时间内重复加载
	 */
	private static final ConcurrentHashMap<String, ChangeLog> logMap = new ConcurrentHashMap<>();

	/**
	 * 添加变动记录
	 * @param path
	 * @param log
	 */
	public static void addChangeLog(String path, ChangeLog log) {
		//之前该文件插入记录了，就把之前的记录删掉，并停止计时器
		ChangeLog old = logMap.remove(path);
		if (old != null) {
			old.stopTimer();
			//前脚刚删了，后脚就加，一般就是类文件更新
			if (log.getChangeType() == Change.ADD && old.getChangeType() == Change.DELETE) {
				log.setChangeType(Change.UPDATE);
			}
		}

		logMap.put(path, log);

	}

	/**
	 * 移除变动记录
	 * @param path
	 */
	public static void removeChangeLog(String path) {
		logMap.remove(path);
	}




	public HotDeployListener(String rootPath) {
		this.rootPath = rootPath;

	}

	@Override
	public void onStop(FileAlterationObserver observer) {
	}
	
	@Override
	public void onStart(FileAlterationObserver observer) {
	}
	
	@Override
	public void onFileDelete(File file) {
		reloadClass(file, Change.DELETE);
	}
	
	@Override
	public void onFileCreate(File file) {
		reloadClass(file, Change.ADD);
	}

	@Override
	public void onFileChange(File file) {
		reloadClass(file, Change.UPDATE);

	}

	private void reloadClass(File file, Change change) {

		String fileName = file.toURI().getPath();

		if (fileName.endsWith(".class")  && fileName.indexOf("$") != -1) return;

		boolean isClass = fileName.endsWith(".class");

		if (isClass) {
			int index = fileName.lastIndexOf(".class");
			fileName = fileName.substring(0, index).replace(rootPath, "").replaceAll( "[/|\\\\]" , ".");
		}

		addChangeLog(fileName, new ChangeLog(isClass, fileName, change));



	}



	@Override
	public void onDirectoryDelete(File directory) {
	}
	
	@Override
	public void onDirectoryCreate(File directory) {
	}
	
	@Override
	public void onDirectoryChange(File directory) {
	}
}
